<?php

namespace app\install\controller;

use app\BaseController;
use app\install\utils\TestDb;
use think\facade\Db;

class Index extends BaseController
{
  public function index()
  {
    if ($this->request->isPost()) {
      //是否安装过
      if (file_exists(root_path('data') . './install.lock')) {
        return _jerr('安装过');
      }
      $out = [
        'version' => config('version.szoa_varsion')
      ];
      return _jok('', $out);
    }
    return _jerr(1000);
  }

  public function step1()
  {
    if ($this->request->isPost()) {
      $dbcon = config('install.data_items');
      $dbcon2 = config('install.redis_items');
      $dbcon = array_merge($dbcon, $dbcon2);
      $out = [
        'env_list' => $this->env_check(),
        'dir_file' => $this->dir_file(),
        'func_list' => $this->func_check(),
      ];
      $out = array_merge($out, $dbcon);
      return _jok('', $out);
    }
    return _jerr(1000);
  }

  //环境变量检测
  private function env_check()
  {
    $data = [];
    $list = config('install.env_items');
    foreach ($list as $key => $val) {
      $data[$key] = $this->env_item_check($val);
    }
    return $data;
  }

  //环境变量一重检测
  private function env_item_check($item)
  {
    $need = ($item['need'] == 'noRestriction') ? '无限制' : $item['need'];
    $icheck = $this->env_item_check_key($item);
    $item = array_merge($item, [
      'need' => $need,
      'res' => $icheck[0],
      'icon' => $icheck[1]
    ]);
    return $item;
  }

  //环境变量二重检测
  private function env_item_check_key($item)
  {
    $data = [];
    switch ($item['key']) {
      case 'PHP_OS':
        $data[0] = PHP_OS;
        $data[1] = 1;
        break;
      case 'SERVER_SOFTWARE':
        $data[0] = $_SERVER[$item['key']];
        $data[1] = 1;
        break;
      case 'PHP_VERSION':
        $data[0] = PHP_VERSION;
        $data[1] = (PHP_VERSION < $item['need']) ? 0 : 1;
        break;
      case 'pdo':
        if (extension_loaded('pdo')) {
          $data[0] = '已安装';
          $data[1] = 1;
        } else {
          $data[0] = '请安装PDO扩展';
          $data[1] = 0;
        }
        break;
      case 'file_uploads':
        if (@ini_get('file_uploads')) {
          $data[0] = ini_get('upload_max_filesize');
          $data[1] = 1;
        } else {
          $data[0] = '未知';
          $data[1] = 0;
        }
        break;
      case 'disk_free_space':
        if (function_exists('disk_free_space')) {
          if (disk_free_space(root_path()) >= mitobyte($item['need'])) {
            $data[0] = file_size_format(disk_free_space(root_path()));
            $data[1] = 1;
          } else {
            $data[0] = file_size_format(disk_free_space(root_path()));
            $data[1] = 0;
          }
        } else {
          $data[0] = '未知';
          $data[1] = 0;
        }
        break;
      case 'gd_info':
        $tmp = function_exists('gd_info') ? gd_info() : array();
        if (empty($tmp['GD Version'])) {
          $data[0] = 'OFF';
          $data[1] = 0;
        } else {
          $data[0] = 'ON - ' . $tmp['GD Version'];
          $data[1] = 1;
        }
        break;
      case 'curl':
        if (extension_loaded('curl')) {
          if (function_exists('curl_init')) {
            $data[0] = 'ON 支持';
            $data[1] = 1;
          } else {
            $data[0] = 'OFF 不支持';
            $data[1] = 0;
          }
        } else {
          $data[0] = '未安装';
          $data[1] = 0;
        }
        break;
      case 'finfo_open':
        if (function_exists('finfo_open')) {
          $data[0] = 'ON 支持';
          $data[1] = 1;
        } else {
          $data[0] = 'OFF 不支持';
          $data[1] = 0;
        }
        break;
      case 'openssl':
        if (extension_loaded('openssl')) {
          if (function_exists('openssl_encrypt')) {
            $data[0] = 'ON 支持';
            $data[1] = 1;
          } else {
            $data[0] = 'OFF 不支持';
            $data[1] = 0;
          }
        } else {
          $data[0] = '未安装';
          $data[1] = 0;
        }
        break;
      case 'bcmath':
        if (function_exists('bcadd')) {
          $data[0] = 'ON 支持';
          $data[1] = 1;
        } else {
          $data[0] = 'OFF 不支持';
          $data[1] = 0;
        }
        break;
      case 'pdo_mysql':
        if (extension_loaded('pdo_mysql')) {
          $data[0] = 'ON 支持';
          $data[1] = 1;
        } else {
          $data[0] = 'OFF 不支持';
          $data[1] = 0;
        }
        break;
      case 'file_put_contents':
        if (function_exists('file_put_contents')) {
          $data[0] = 'ON 支持';
          $data[1] = 1;
        } else {
          $data[0] = 'OFF 不支持';
          $data[1] = 0;
        }
        break;
      case 'file_get_contents':
        if (function_exists('file_get_contents')) {
          $data[0] = 'ON 支持';
          $data[1] = 1;
        } else {
          $data[0] = 'OFF 不支持';
          $data[1] = 0;
        }
        break;
      case 'xml_parser_create':
        if (function_exists('xml_parser_create')) {
          $data[0] = 'ON 支持';
          $data[1] = 1;
        } else {
          $data[0] = 'OFF 不支持';
          $data[1] = 0;
        }
        break;
      case 'gethostbyname':
        if (function_exists('gethostbyname')) {
          $data[0] = 'ON 支持';
          $data[1] = 1;
        } else {
          $data[0] = 'OFF 不支持';
          $data[1] = 0;
        }
        break;
      case 'fsockopen':
        if (function_exists('fsockopen')) {
          $data[0] = 'ON 支持';
          $data[1] = 1;
        } else {
          $data[0] = 'OFF 不支持';
          $data[1] = 0;
        }
        break;
      case 'imagettftext':
        if (function_exists('imagettftext')) {
          $data[0] = 'ON 支持';
          $data[1] = 1;
        } else {
          $data[0] = 'OFF 不支持';
          $data[1] = 0;
        }
        break;
      default:
        $data[0] = '无数据';
        $data[1] = 0;
        break;
    }
    return $data;
  }

  //目录、文件权限检查
  private function dir_file()
  {
    $dir_items =  config('install.dir_items');
    $rootPath = root_path();
    $dirData = [];
    foreach ($dir_items as $dir) {
      $Testdir = $rootPath . $dir;
      $dirData[$dir] = [
        'key' => $dir,
        'name' => $dir,
        'need' => '可读写',
        'reco' => '可读写'
      ];
      if (!is_file($Testdir)) {
        if (!is_dir($Testdir)) {
          dir_create($Testdir);
        }
      }
      if (testwrite($Testdir)) {
        $dirData[$dir]['res_w'] = '可写';
        $dirData[$dir]['icon_w'] = 1;
      } else {
        $dirData[$dir]['res_w'] = '不可写';
        $dirData[$dir]['icon_w'] = 0;
      }
      if (is_readable($Testdir)) {
        $dirData[$dir]['res_r'] = '可读';
        $dirData[$dir]['icon_r'] = 1;
      } else {
        $dirData[$dir]['res_r'] = '不可读';
        $dirData[$dir]['icon_r'] = 0;
      }
    }
    return $dirData;
  }

  //依赖函数
  private function func_check()
  {
    $res = [];
    $func_items =  config('install.function_items');
    foreach ($func_items as $key => $item) {
      $res[$key] = $this->func_item_check($item);
    }
    return $res;
  }

  //依赖函数一重检测
  private function func_item_check($item)
  {
    $icheck = $this->func_item_check_key($item['key']);
    $item = array_merge($item, [
      'reco' => $item['reco'] == 'noRestriction' ? '无限制' : $item['reco'],
      'res' => $icheck[0],
      'icon' => $icheck[1],
      'jctg' => $item['reco'] == 'noRestriction' ? 1 : $icheck[1],
    ]);

    return $item;
  }

  //依赖函数二重检测
  private function func_item_check_key($func_item)
  {
    $data = [];
    if (function_exists($func_item) || extension_loaded($func_item)) {
      $data[0] = 'ON 支持';
      $data[1] = 1;
    } else {
      $data[0] = 'OFF 不支持';
      $data[1] = 0;
    }
    return $data;
  }

  /**
   * 获取云端验证码
   */
  public function yuncode()
  {
    if (request()->isGet()) {
      $url = config('kaige.authorization_url') . '/api/captcha';
      $data = $this->curl_noheader($url, [], ['result' => 'json']);
      if ($data) {
        return _jok('', $data);
      }
      return _jerr(1004);
    }
    return _jerr(1000);
  }

  /**
   * 云端发送短信
   */
  public function yunsms()
  {
    if (request()->isPost()) {
      $data = input('param.');
      if (!isset($data['mobile'])) {
        return _jerr(1002);
      }
      if (!isMobile($data['mobile'])) {
        return _jerr('手机号不正确');
      }
      if (empty($data['captcha'])) {
        return _jerr(2109);
      }
      if (empty($data['key'])) {
        return _jerr(2109);
      }
      $data['ip'] = _gip();
      $url = config('kaige.authorization_url') . '/api/install/sendsms';
      $result = $this->curl_noheader($url, $data, ['result' => 'json', 'method' => 'POST']);
      if ($result) {
        return _jok('', $result);
      }
      return _jerr(1004);
    }
    return _jerr(1000);
  }

  /**
   * Curl请求
   * @param string $url   链接
   * @param array $data   传入数据,只支持一维数组
   * @param array $arr    其它参数
   * @return bool|string
   */
  public function curl_noheader($url = '', $data = [], $arr = [])
  {
    if (empty($url)) {
      return false;
    }

    //处理 header
    $header = [];
    if (!isset($arr['header'])) {
      $header[] = "content-type:application/x-www-form-urlencoded;charset=utf-8";
    } else {
      $header = $arr['header'];
    }
    if (!isset($arr['method'])) {
      $method = 'GET';
    } else {
      $method = $arr['method'];
    }
    if (!isset($arr['timeout'])) {
      $timeout = 5;
    } else {
      $timeout = $arr['timeout'];
    }

    // curl完成初始化
    $curl = curl_init();
    if (defined('CURLOPT_IPRESOLVE') && defined('CURL_IPRESOLVE_V4')) {
      curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); //强制使用IPV4协议解析域名
    }

    if ($data) {
      foreach ($data as $key => $val) {
        $data[$key] =  urlencode($val);
      }
      //数组排序
      ksort($data);
      foreach ($data as $k9 => &$v9) { //一层数组排一下序
        if (is_array($v9)) {
          ksort($v9);
        }
      }
      $upstr = http_build_query($data);
    } else {
      $upstr = '';
    }

    //默认是GET请求,仅2种 GET,POST
    switch (strtoupper($method)) {
      case 'GET':
        $url = $url . '?' . $upstr; //只能用 url传参
        break;
      case 'POST':
        curl_setopt($curl, CURLOPT_POST, 1); //请求方式为post请求
        curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data)); //请求数据
        break;
      default:
        return false; //中断返回
    }
    curl_setopt($curl, CURLOPT_URL, $url); //需要获取的URL地址
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); //只获取页面内容，但不输出
    if (stripos($url, "https://") !== false) {
      curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); //https请求 不验证证书
      curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); //https请求 不验证HOST
      curl_setopt($curl, CURLOPT_SSLVERSION, 1); //设置SSL协议版本号
    }
    curl_setopt($curl, CURLOPT_TIMEOUT, $timeout); //超时
    curl_setopt($curl, CURLOPT_HTTPHEADER, $header); //模拟的header头
    curl_setopt($curl, CURLINFO_HEADER_OUT, 1); //启用时追踪句柄的请求字符串

    $result = curl_exec($curl); //执行请求--结果一般是字符串
    // $headertxt = curl_getinfo($curl, CURLINFO_HEADER_OUT);
    $result_info  = curl_getinfo($curl); //获取连接资源句柄的信息
    curl_close($curl); //关闭curl，释放资源
    if (intval($result_info["http_code"]) == 200) {
      if ($arr['result'] == 'json') { //如果知道 返回结果是json 则转换
        $result = json_decode($result, true);
      }
      return $result;
    } else {
      return false;
    }
  }

  /**
   * 云端注册手机用户
   */
  public function yunreguser()
  {
    if (request()->isPost()) {
      $data = input('param.');
      if (!isset($data['mobile'])) {
        return _jerr(1002);
      }
      if (!isMobile($data['mobile'])) {
        return _jerr('手机号不正确');
      }
      $data['ip'] = _gip();
      $url = config('kaige.authorization_url') . '/api/install/reguser';
      $result = $this->curl_noheader($url, $data, ['result' => 'json', 'method' => 'POST']);
      return _jok('', $result);
    }
    return _jerr(1000);
  }


  /**
   * 写配置env
   */
  public function writeenv()
  {
    if (request()->isPost()) {
      $data = input('param.');
      $result = $this->makeenv($data);
      if (class_exists('Redis')) { // 是否支持Redis
        cache('install_data', $data); //缓存
        return json($result);
      } else {
        return _jerr('请配置或安装Redis！！！');
      }
      // $postData['onlydb_host'] = env('DATABASE.HOSTNAME');
      // $postData['onlydb_port'] = env('DATABASE.HOSTPORT');
      // $postData['onlydb_user'] = env('DATABASE.USERNAME');
      // $postData['onlydb_pwd'] = env('DATABASE.PASSWORD');
      // $postData['onlydb_name'] = env('DATABASE.DATABASE');
      // $postData['onlydb_prefix'] = env('DATABASE.PREFIX');
      return json();
    }
    return _jerr(1000);
  }

  /**
   * 写配置
   */
  public function makeseting()
  {
    if (request()->isPost()) {
      $data = input('param.');
      if (isset($data['mobile']) && !empty($data['mobile'])) {
        $this->makekaige($data);
        $this->makeszoajs($data);
        if (class_exists('Redis')) { // 是否支持Redis
          $postData = cache('install_data'); //取已存配置
          $data = array_merge($data, $postData);
          cache('install_data', $data); //缓存
          return _jok('ok');
        } else {
          return _jerr('请配置或安装Redis！！！');
        }
      }
      return _jerr(1004);
    }
    return _jerr(1000);
  }

  /**
   * 目录是否存在，不存在则创建
   * @param $dir
   */
  protected function isDir($dir)
  {
    if (!is_dir($dir)) {
      mkdir($dir, 0777, true);
    }
  }

  /**
   * 生成后端配置--kaige.php
   */
  protected function makekaige($data = [])
  {
    // 拼成页面内容
    $template = '<?php
// +--------------------------------
// | 站点配置
// +--------------------------------

return [
  \'domain_name\' => \'' . (is_https() === false ? 'http://' : 'https://') . $data['domain'] . '\', //站点域名，不含最后一个斜扛
  \'default_image\' => \'/static/img/default.png\',
  \'login_fail_num\' => 3, //登陆失败次数，如果每天登陆失败次数超过次数字，就会显示图片验证码
  \'sys_login_fail_num\' => 5, //管理员登陆失败次数，如果超过这个次数，会显示图片验证码，防止暴力破解
  \'sys_uid_loginkey\' => \'szoa_user_login_uids\',  //记录用户是否已经登录的keys
  \'version\' => \'v1.1.0\', //版本号
  \'cache_key\'=>\'kaige_cache_\', //缓存key左边
  \'kai_url\' => \'//' . $data['domain'] . '\', // 资源域名路径
  \'idworkid\' => 8,  // 当前服务器workid 定义（1-1023）
  \'jwt_secret_key\'     => \'' . get_rand_str(32) . '\', // 32位随机数定义为secret key
  \'jwt_algorithm\'      => \'HS256\', // jwt算法 ，可配置的值取决于使用的jwt包支持哪些算法
  \'pass_salt\'          => \'' . get_rand_str(16) . '\',     //加密盐值
  \'app_sign_auth_on\'   => true, // 是否开启app接口签名认证
  \'app_sign_white_url\' => [
      \'api/upload/upfiles\',
      \'api/upload/down\',
      \'backend/files/upfiles\',
      \'backend/files/down\',
      \'api/login/index\',
      \'backend/index/logout\',
      \'backend/sys.dbase/export\',
      \'backend/sys.dbase/optimize\',
      \'backend/sys.dbase/repair\',
  ], // 控制器免签白名单(小写)
  \'app_sign_key\'       => \'' . get_rand_str(20) . '\', // app接口加密安全key
  \'user_last_time\'     => 28800, // 用户登录有效期8小时
  \'domain\'             => \'' . $data['domain'] . '\', //允许跨域域名
  \'super_id\'           => env(\'SUPER_ID\',425),
  // 跨域header
  \'header\'    => [
      \'Access-Control-Allow-Credentials\' => \'true\',
      \'Access-Control-Max-Age\'       => 1800,
      \'Access-Control-Allow-Methods\' => \'GET, POST, PATCH, PUT, DELETE,OPTIONS\',
      \'Access-Control-Allow-Headers\' => \'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-Requested-With,Kg-Appid, Kg-Token\',
  ],
  // token名称
  \'token_name\' => \'Kg-Token\',
  \'file_max_size\'=> 52428800, //上传文件限制50M
  // 允许上传文件扩展名
  \'file_ext\' => \'jpg,png,gif,bmp,ico,zip,avi,mp3,mp4,wav,txt,doc,docx,xls,xlsx,ppt,pptx,pdf\',
  // 允许上传文件类型
  \'file_mime\'=> \'image/gif,image/jpeg,image/pjpeg,image/png,image/x-png,image/bmp,image/x-icon,application/zip,application/x-zip-compressed,video/avi,audio/mpeg,video/mp4,audio/wav,text/plain,application/msword,application/vnd.ms-excel,application/vnd.ms-powerpoint,application/pdf\',
  \'file_domain\'=>false, //文件url是否加上指定的域名
  \'open_make_curd\'=>false, //是否开启可自动生成 CURD --开发模式true,生产环境时请关闭 设为false
  \'product\'=>\'SZOA\',
  \'authorization_url\'=>\'https://s.shengzhuoa.com\', // 禁止更改此域名，否则将不能更新
];
';
    // 文件路径
    $kaigefilePath = config_path() . '/kaige.php';
    // 会进行覆盖原文件
    file_put_contents($kaigefilePath, $template);
    return _ok('后端配置成功：' . $kaigefilePath);
  }

  /**
   * 生成前端配置--szconfig.js
   */
  protected function makeszoajs($data = [])
  {
    $appid = get_rand2619(18);
    $appSecret = get_rand2619(32);
    //加入缓存
    cache('install_appid', $appid);
    cache('install_appSecret', $appSecret);

    $template = 'window.szconfig = {
      url:"' . (is_https() === false ? 'http://' : 'https://') . $data['domain'] . '/' . '"
      , domain: "' . $data['domain'] . '"
      , module: "' . 'backend' . '"
      , path: "' . '/pc' . '"
      , appid: "' . $appid . '"
      , appSecret: "' . $appSecret . '"
      , expires: 28800
      , tokenKey: "' . 'Kg-Token' . '"
      , userinfoKey: "' . 'User-Info' . '"
      , websocketUrl: "' . (is_https() === false ? ('ws://' . $data['domain'] . ':22336/') : ('wss://' . $data['domain'] . '/wss/')) . '"
      , uploadUrl: "' . 'backend/files/upfiles' . '"
      , idcSrc: "' . '//' . $data['domain'] . '/static/video/message.mp3' . '"
    }';

    // 文件路径
    $szoajsfilePath = public_path() . '/pc/static/kaige/js/szconfig.js';
    // 会进行覆盖原文件
    file_put_contents($szoajsfilePath, $template);
    return _ok('前端配置成功：' . $szoajsfilePath);
  }

  /**
   * ENV(数据库、Redis等配置)
   */
  public function makeenv($data = [])
  {
    $template = '
APP_DEBUG = false
SUPER_ID = 425
COMPANY_ID = 11

[APP]
DEFAULT_TIMEZONE = Asia/Shanghai

[DATABASE]
TYPE = mysql
HOSTNAME = ' . $data['onlydb_host'] . '
HOSTPORT = ' . $data['onlydb_port'] . '
USERNAME = ' . $data['onlydb_user'] . '
PASSWORD = ' . $data['onlydb_pwd'] . '
DATABASE = ' . $data['onlydb_name'] . '
PREFIX = ' . $data['onlydb_prefix'] . '
CHARSET = utf8
DEBUG = false

[LANG]
default_lang = zh-cn

[REDIS]
REDIS_HOSTNAME = ' . $data['redis_host'] . '
PORT = ' . $data['redis_port'] . '
REDIS_PASSWORD = ' . $data['redis_pwd'] . '
SELECT = 0
';
    // 文件路径
    $envfilePath = root_path() . '.env';
    // 会进行覆盖原文件
    file_put_contents($envfilePath, $template);
    return _ok('Env配置成功：' . $envfilePath);
  }

  private function sql_split($sql, $prefix)
  {
    $sql = preg_replace('/(\/\*.*\*\/)/s', '', $sql);
    //替换 DROP TABLE IF EXISTS
    $sql = preg_replace('/DROP TABLE IF EXISTS `([\S]+_)/isU', 'DROP TABLE IF EXISTS `' . $prefix, $sql);
    //替换 CREATE TABLE
    $sql = preg_replace('/CREATE TABLE `([\S]+_)/isU', 'CREATE TABLE `' . $prefix, $sql);
    //替换 INSERT INTO `
    $sql = preg_replace('/INSERT INTO `([\S]+_)/isU', 'INSERT INTO `' . $prefix, $sql);
    //替换
    $sql = preg_replace("/TYPE=(InnoDB|MyISAM|MEMORY)( DEFAULT CHARSET=[^; ]+)?/", "ENGINE=\\1 DEFAULT CHARSET=utf8", $sql);
    //替换换行符
    $sql = str_replace("\r", "\n", $sql);
    $ret = array();
    $num = 0;
    $queriesArr = explode(";\n", trim($sql));
    unset($sql);
    foreach ($queriesArr as $query) {
      $ret[$num] = '';
      $queries = explode("\n", trim($query));
      $queries = array_filter($queries);

      foreach ($queries as $query) {
        $str1 = substr($query, 0, 1);
        if ($str1 != '#' && $str1 != '-' && $query != 'BEGIN' && $query != 'COMMIT')
          $ret[$num] .= $query;
      }
      $num++;
    }
    return $ret;
  }

  public function installing()
  {
    if (request()->isPost()) {
      $res = [];
      $step = 0;     //第几步  1
      $step_sub = 0; //步骤子项数 1-1，1-2

      $s = input('s'); //过程步骤 1 step 
      $ss = intval(input('ss')); //过程子步骤 1-1 setp sub
      $status = input('status'); //过程状态记录器
      $res['status'] = $status;

      $postData = cache('install_data');

      //第一步数据初始化处理
      if ($s[0] == ++$step && !intval($s[3])) { // 初始 $s[0] = 1;  ++$step 从0开始 也是1 ++在前即 先+值变； $s[3] 为0 ！0=true
        //1-0-0
        if ($s[1] == $step_sub++) { //$s[1]初始为0 = $step_sub 先赋值 后再加；// true
          $s = [$step, $step_sub, 'ready_to_load_predefined_data', '0'];
          $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 1,  'title' => '数据初始化处理', 'content' => '准备载入预定义数据！', 'msg' => ''];
          return json($res);
        }

        if ($s[1] == $step_sub++) {
          $s = [++$step, 0, '', '0'];
          $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 1,  'title' => '数据初始化处理', 'content' => '准备数据库创建！', 'msg' => ''];
          return json($res);
        }
      }

      //第二步创建数据库
      if ($s[0] == ++$step && !intval($s[3])) {
        //2-0-0
        if ($s[1] == $step_sub++) {
          $s = [$step, $step_sub, '', '0'];
          $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 2,  'title' => '创建数据库', 'content' => '判断是否安装PDO_MYSQL扩展！', 'msg' => ''];
          return json($res);
        }
        //2-1-0
        if ($s[1] == $step_sub++) {
          if (!extension_loaded('pdo_mysql')) {
            $s = [$step, $step_sub, '', '0'];
            $res = ['status' => -2, 'flag' => 0, 's' => $s, 'ss' => $ss, 'tid' => 2,  'title' => '创建数据库', 'content' => '请安装 pdo_mysql 扩展！', 'msg' => ''];
            return json($res);
          }
          $s = [$step, $step_sub, '', '0'];
          $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 2,  'title' => '创建数据库', 'content' => 'PDO_MYSQL扩展存在，准备采集处理数据库预定义参数！', 'msg' => ''];
          return json($res);
        }
        //2-2-0
        if ($s[1] == $step_sub++) {
          $s = [$step, $step_sub, 'createDB_start', '0'];
          $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 2,  'title' => '创建数据库', 'content' => '准备处理！', 'msg' => ''];
          return json($res);
        }
        //2-3-0
        if ($s[1] == $step_sub++) {
          $conn = new \PDO("mysql:host=" . $postData['onlydb_host'] . ";port=" . $postData['onlydb_port'] . "", $postData['onlydb_user'], $postData['onlydb_pwd']);
          $connStatus = pdo_ping($conn);
          if ($connStatus) { //连接存在
            //2-3-0
            if ($s[2] == 'createDB_start') {
              $s = [$step, $step_sub - 1, 'createDB_conn', '0'];
              $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 2,  'title' => '创建数据库', 'content' => '连接数据库成功，开始创建 ' . $postData['onlydb_name'] . ' 数据库！', 'msg' => ''];
              return json($res);
            }
            $db_isCreated = $conn->prepare("SHOW TABLES FROM `" .  $postData['onlydb_name'] . "`")->execute();
            if ($db_isCreated) { //数据库存在
              //2-3-1
              if ($s[2] == 'createDB_conn') {
                $s = [$step, $step_sub - 1, 'createDB_del', '0'];
                $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 2,  'title' => '创建数据库', 'content' => $postData['onlydb_name'] . ' 数据库存在，准备执行删除 ' .  $postData['onlydb_name'] . ' 数据库！', 'msg' => ''];
                return json($res);
              }
              //2-3-2
              if ($s[2] == 'createDB_del') {
                $delDb = $conn->prepare("DROP DATABASE IF EXISTS  `" .  $postData['onlydb_name'] . "`")->execute();
                if ($delDb) {
                  $s = [$step, $step_sub - 1, 'createDB_del_ok', '0'];
                  $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 2,  'title' => '创建数据库', 'content' => $postData['onlydb_name'] . ' 数据库删除成功，准备执行创建 ' .  $postData['onlydb_name'] . ' 数据库！', 'msg' => ''];
                  return json($res);
                } else {
                  $s = [$step, $step_sub - 1, 'createDB_del_fail', '0'];
                  $res = ['status' => -2, 'flag' => 0, 's' => $s, 'ss' => $ss, 'tid' => 2,  'title' => '创建数据库', 'content' => $postData['onlydb_name'] . ' 数据库删除失败，终止运行！', 'msg' => ''];
                  return json($res);
                }
              }
            } else { //数据库不存在
              $createDB = $conn->prepare("CREATE DATABASE IF NOT EXISTS  `" .  $postData['onlydb_name'] . "`")->execute();
              //2-3-3
              if ($createDB) {
                $s = [$step, $step_sub, 'createDB_end', '0'];
                $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 2,  'title' => '创建数据库', 'content' => '创建数据库 ' .  $postData['onlydb_name'] . ' 成功！', 'msg' => ''];
                return json($res);
              } else {
                $s = [$step, $step_sub, 'createDB_fail', '0'];
                $res = ['status' => -2, 'flag' => 0, 's' => $s, 'ss' => $ss, 'tid' => 2,  'title' => '创建数据库', 'content' => '创建数据库 ' .  $postData['onlydb_name'] . ' 失败，不能连接数据库！', 'msg' => ''];
                return json($res);
              }
            }
          } else {
            //2-3-4
            $s = [$step, $step_sub, 'createDB_fail', '0'];
            $res = ['status' => -2, 'flag' => 0, 's' => $s, 'ss' => $ss, 'tid' => 2,  'title' => '创建数据库', 'content' => '创建数据库 ' .  $postData['onlydb_name'] . ' 失败，不能连接数据库！', 'msg' => ''];
            return json($res);
          }
        }
        //2-4-0
        if ($s[1] == $step_sub++) {
          $s = [++$step, 0, '', '0'];
          $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 2,  'title' => '创建数据库', 'content' => '完成数据库创建，准备数据表创建！', 'msg' => ''];
          return json($res);
        }
      }
      //第三步创建数据库表结构 3-0-0
      if ($s[0] == ++$step && !intval($s[3])) {
        //3-0-0
        if ($s[1] == $step_sub++) {
          $s = [$step, $step_sub, '', '0'];
          $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 3,  'title' => '创建数据表结构', 'content' => '采集数据表结构文件，准备创建！', 'msg' => ''];
          return json($res);
        }
        $dbDir = public_path() . '/install/db/';
        $dbInfo = [
          'sqlFile' => 'szoa.sql'
        ];
        //3-1-0
        if ($s[1] == $step_sub++) {
          $s = [$step, $step_sub, 'createTable_start', '0'];
          $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 3,  'title' => '创建数据表结构', 'content' => '准备采集数据表配置信息！', 'msg' => ''];
          return json($res);
        }
        // 数据库设定 3-2-0
        if ($s[1] == $step_sub++) {
          $config = array(
            'host' => $postData['onlydb_host'],
            'port' => $postData['onlydb_port'],
            'dbname' => $postData['onlydb_name'],
            'user' => $postData['onlydb_user'],
            'password' => $postData['onlydb_pwd'],
            'pconnect' => 0,
            'charset' => 'utf8'
          );
          $conn = TestDb::get_mysqlconn($config);
          $connStatus = pdo_ping($conn);
          if ($connStatus) {
            //读取数据文件 3-2-0
            if ($s[2] == 'createTable_start') {
              $s = [$step, $step_sub - 1, 'createTable_conn_OK', '0'];
              $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 3,  'title' => '创建数据表结构', 'content' => '连接 ' . $postData['onlydb_name'] . ' 数据库成功，准备创建数据表！', 'msg' => ''];
              return json($res);
            }
            $installTableSqlFile = realpath($dbDir . $dbInfo['sqlFile']) ? file_get_contents(realpath($dbDir . $dbInfo['sqlFile'])) : false;
            $sqlFormat = self::sql_split($installTableSqlFile, $postData['onlydb_prefix']);
            //执行SQL
            $counts = count($sqlFormat);
            for ($n = $ss; $n < $counts; $n++) {
              $sql = trim($sqlFormat[$n]);
              if (strstr($sql, 'CREATE TABLE')) {
                preg_match('/CREATE TABLE `([A-Za-z0-9]+)_([^ ]*)`/is', $sql, $matches);
                $sql = str_replace('`' . $matches[1] . '_', '`' . $postData['onlydb_prefix'], $sql); //替换表前缀
                $ret = $conn->prepare($sql)->execute();
                if ($ret) {
                  //3-2-1 n
                  $s = [$step, $step_sub - 1, 'CREATE_TABLE_' . $matches[2] . '_OK', '0'];
                  $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 4,  'title' => '创建数据表', 'content' =>  '第' . $n . '条SQL语句:创建数据表' . $matches[1] . '_' . $matches[2] . '--执行SQL创建成功！', 'msg' => ''];
                  $res['ss'] = ++$n;
                  return json($res);
                } else {
                  //3-2-1 n
                  $s = [$step, $step_sub - 1, 'CREATE_TABLE_' . $matches[1] . '_fail', '0'];
                  $res = ['status' => -2, 'flag' => 0, 's' => $s, 'ss' => $ss, 'tid' => 4,  'title' => '创建数据表', 'content' => '第' . $n . '条SQL语句:创建数据表' . $matches[1] . '_' . $matches[2] . '--执行SQL创建失败！', 'msg' => ''];
                  $res['ss'] = ++$n;
                  return json($res);
                }
              } else {
                if (trim($sql) == '') continue;
                if (strstr($sql, 'DROP TABLE')) {
                  preg_match('/DROP TABLE IF EXISTS `([A-Za-z0-9]+)_([^ ]*)`/is', $sql, $matches);
                } elseif (strstr($sql, 'INSERT INTO')) {
                  preg_match('/INSERT INTO `([A-Za-z0-9]+)_([^ ]*)`/is', $sql, $matches);
                } else {
                  continue;
                }
                $sql = str_replace('`' . trim($matches[1]) . '_', '`' . $postData['onlydb_prefix'], $sql); //替换表前缀
                $ret = $conn->prepare($sql)->execute();
                if ($ret) {
                  //3-2-3 n
                  $s = [$step, $step_sub - 1, 'ExecuteSQL_OK', '0'];
                  $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 4,  'title' => '创建数据表', 'content' => $matches[1] . '_' . $matches[2] . ' 第' . $n . '条SQL语句:`' . mb_substr($sql, 0, 18) . '...`--执行SQL成功！', 'msg' => ''];
                  $res['ss'] = ++$n;
                  // $res['sql'] = $sql;
                  return json($res);
                } else {
                  //3-2-3 n
                  $s = [$step, $step_sub - 1, 'ExecuteSQL_fail', '0'];
                  $res = ['status' => 0, 'flag' => 0, 's' => $s, 'ss' => $ss, 'tid' => 4,  'title' => '创建数据表', 'content' =>  $matches[1] . '_' . $matches[2] . ' 第' . $n . '条SQL语句:`' . mb_substr($sql, 0, 18) . '...`--执行SQL失败！', 'msg' => ''];
                  $res['ss'] = ++$n;
                  $res['sql'] = $sql;
                  return json($res);
                }
              }
            }
            //创建成功 3-3-0
            $s = [$step, $step_sub, 'createTable_end', '0'];
            $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 4,  'title' => '创建数据表', 'content' => '数据表全部创建完成！', 'msg' => ''];
            $res['ss'] = 0;
            return json($res);
          } else { //3-3-1
            $s = [$step, $step_sub, 'createTable_fail', '0'];
            $res = ['status' => -2, 'flag' => 0, 's' => $s, 'ss' => $ss, 'tid' => 4,  'title' => '创建数据表', 'content' => '创建数据表失败，不能连接数据库！', 'msg' => ''];
            $res['ss'] = 0;
            return json($res);
          }
        }
        //3-4
        if ($s[1] == $step_sub++) {
          $s = [++$step, 0, '', '0'];
          $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => 0, 'tid' => 4,  'title' => '创建数据表', 'content' => '完成数据库的所有数据表创建，准备基础数据添加！', 'msg' => ''];
          return json($res);
        }
      }

      //第四步 添加基础数据 4-0-0
      if ($s[0] == ++$step && !intval($s[3])) {
        //4-0-0
        if ($s[1] == $step_sub++) {
          $s = [$step, $step_sub, '', '0'];
          $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 5,  'title' => '添加基础数据', 'content' => '采集基础数据文件，准备创建！', 'msg' => ''];
          return json($res);
        }
        $dbDir = public_path() . '/install/db/';
        $basesql = 'base.sql';
        //4-1-0
        if ($s[1] == $step_sub++) {
          $s = [$step, $step_sub, 'insertData_start', '0'];
          $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 5,  'title' => '添加基础数据', 'content' => '采集基础数据配置信息！', 'msg' => ''];
          return json($res);
        }
        //4-2-0
        if ($s[1] == $step_sub++) {
          $config = array(
            'host' => $postData['onlydb_host'],
            'port' => $postData['onlydb_port'],
            'dbname' => $postData['onlydb_name'],
            'user' => $postData['onlydb_user'],
            'password' => $postData['onlydb_pwd'],
            'pconnect' => 0,
            'charset' => 'utf8'
          );
          $conn = TestDb::get_mysqlconn($config);
          $connStatus = pdo_ping($conn);
          if ($connStatus) {
            //读取文件 4-2-0
            if ($s[2] == 'insertData_start') {
              $s = [$step, $step_sub - 1, 'insertData_conn_OK', '0'];
              $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 5,  'title' => '添加基础数据', 'content' => '连接 ' . $postData['onlydb_name'] . ' 数据库成功，准备添加！', 'msg' => ''];
              return json($res);
            }
            $installTableSqlFile = realpath($dbDir . $basesql) ? file_get_contents(realpath($dbDir . $basesql)) : false;
            $sqlFormat = self::sql_split($installTableSqlFile, $postData['onlydb_prefix']);
            //执行SQL
            $counts = count($sqlFormat);
            for ($n = $ss; $n < $counts; $n++) {
              $sql = trim($sqlFormat[$n]);
              if (strstr($sql, 'CREATE TABLE')) {
                preg_match('/CREATE TABLE `([A-Za-z0-9]+)_([^ ]*)`/is', $sql, $matches);
                $sql = str_replace('`' . $matches[1] . '_', '`' . $postData['onlydb_prefix'], $sql); //替换表前缀
                $ret = $conn->prepare($sql)->execute();
                if ($ret) {
                  //4-2-1 n
                  $s = [$step, $step_sub - 1, 'INSERT_TABLE_' . $matches[2] . '_OK', '0'];
                  $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 5,  'title' => '添加基础数据', 'content' => '第' . $n . '条SQL语句:添加基础数据' . $matches[1] . '_' . $matches[2] . '--执行SQL创建成功！', 'msg' => ''];
                  $res['ss'] = ++$n;
                  return json($res);
                } else {
                  //4-2-1 n
                  $s = [$step, $step_sub - 1, 'INSERT_TABLE_' . $matches[1] . '_fail', '0'];
                  $res = ['status' => -2, 'flag' => 0, 's' => $s, 'ss' => $ss, 'tid' => 5,  'title' => '添加基础数据', 'content' => '第' . $n . '条SQL语句:添加基础数据' . $matches[1] . '_' . $matches[2] . '--执行SQL创建失败！', 'msg' => ''];
                  $res['ss'] = ++$n;
                  return json($res);
                }
              } else {
                if (trim($sql) == '') continue;
                if (strstr($sql, 'DROP TABLE')) {
                  preg_match('/DROP TABLE IF EXISTS `([A-Za-z0-9]+)_([^ ]*)`/is', $sql, $matches);
                } elseif (strstr($sql, 'INSERT INTO')) {
                  preg_match('/INSERT INTO `([A-Za-z0-9]+)_([^ ]*)`/is', $sql, $matches);
                } else {
                  continue;
                }
                $sql = str_replace('`' . trim($matches[1]) . '_', '`' . $postData['onlydb_prefix'], $sql); //替换表前缀
                $ret = $conn->prepare($sql)->execute();
                if ($ret) {
                  //4-2-3 n
                  $s = [$step, $step_sub - 1, 'INSERTSQL_OK', '0'];
                  $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 5,  'title' => '添加基础数据', 'content' => '第' . $n . '条SQL语句:`' . mb_substr($sql, 0, 12) . '...`--执行SQL成功！', 'msg' => ''];
                  $res['ss'] = ++$n;
                  return json($res);
                } else {
                  //4-2-3 n
                  $s = [$step, $step_sub - 1, 'INSERTSQL_fail', '0'];
                  $res = ['status' => 0, 'flag' => 0, 's' => $s, 'ss' => $ss, 'tid' => 5,  'title' => '添加基础数据', 'content' => '第' . $n . '条SQL语句:`' . mb_substr($sql, 0, 12) . '...`--执行SQL失败！', 'msg' => ''];
                  $res['ss'] = ++$n;
                  $res['sql'] = $sql;
                  return json($res);
                }
              }
            }
            //创建成功 4-3-0
            $s = [$step, $step_sub, 'insertTable_end', '0'];
            $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 5,  'title' => '添加基础数据', 'content' => '全部添加完成！', 'msg' => ''];
            $res['ss'] = 0;
            return json($res);
          } else { //4-3-1
            $s = [$step, $step_sub, 'insertTable_fail', '0'];
            $res = ['status' => -2, 'flag' => 0, 's' => $s, 'ss' => $ss, 'tid' => 5,  'title' => '添加基础数据', 'content' => '添加数据失败，不能连接数据库！', 'msg' => ''];
            $res['ss'] = 0;
            return json($res);
          }
        }
        //4-4
        if ($s[1] == $step_sub++) {
          $s = [++$step, 0, '', '0'];
          $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => 0, 'tid' => 5,  'title' => '添加基础数据', 'content' => '完成所有数据添加，准备添加管理员！', 'msg' => ''];
          return json($res);
        }
      }

      //第五步添加管理员
      if ($s[0] == ++$step && !intval($s[3])) {
        if ($s[1] == $step_sub++) {
          $s = [$step, $step_sub, 'get_admin_set', '0'];
          $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 6,  'title' => '添加管理员', 'content' => '采集管理员配置参数！', 'msg' => ''];
          return json($res);
        }

        if ($s[1] == $step_sub++) {
          $add_managerFlag = $this->add_manager();
          if ($add_managerFlag) {
            $s = [$step, $step_sub, 'add_manage_ok', '0'];
            $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 6,  'title' => '添加管理员', 'content' => '写入管理员信息成功！', 'msg' => ''];
            return json($res);
          } else {
            $s = [$step, $step_sub, 'add_manage_fail', '0'];
            $res = ['status' => -2, 'flag' => 0, 's' => $s, 'ss' => $ss, 'tid' => 6,  'title' => '添加管理员', 'content' => '写入管理员信息失败！', 'msg' => ''];
            return json($res);
          }
        }
        if ($s[1] == $step_sub++) {
          $s = [++$step, 0, '', '0'];
          $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 6,  'title' => '添加管理员', 'content' => '完成管理员信息创建！', 'msg' => ''];
          return json($res);
        }
      }

      //第六步添加客户端
      if ($s[0] == ++$step && !intval($s[3])) {
        if ($s[1] == $step_sub++) {
          $s = [$step, $step_sub, 'get_client_set', '0'];
          $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 7,  'title' => '添加客户端', 'content' => '添加客户端配置！', 'msg' => ''];
          return json($res);
        }

        if ($s[1] == $step_sub++) {
          $add_clientFlag = $this->add_client();
          if ($add_clientFlag) {
            $s = [$step, $step_sub, 'add_client_ok', '0'];
            $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 7,  'title' => '添加客户端', 'content' => '写入客户端信息成功！', 'msg' => ''];
            return json($res);
          } else {
            $s = [$step, $step_sub, 'add_client_fail', '0'];
            $res = ['status' => -2, 'flag' => 0, 's' => $s, 'ss' => $ss, 'tid' => 7,  'title' => '添加客户端', 'content' => '写入客户端信息失败！', 'msg' => ''];
            return json($res);
          }
        }
        if ($s[1] == $step_sub++) {
          $s = [++$step, 0, '', '0'];
          $res = ['status' => 0, 'flag' => 1, 's' => $s, 'ss' => $ss, 'tid' => 7,  'title' => '添加客户端', 'content' => '完成客户端信息创建！', 'msg' => ''];
          return json($res);
        }
      }
      //写入install.lock
      @touch(root_path('data') . './install.lock');
      $arr['step'] = $step;
      $arr['status'] = 'finish';
      $arr['msg'] = '完成';
      return json($arr);
    }
    return _jerr(1000);
  }

  public function add_manager()
  {
    $postData = cache('install_data');
    //添加管理员
    $pwd = $postData['onlydb_user_pwd'];
    $data = [
      'un' => $postData['onlydb_user_account'],
      'id' => 425, // 对应env 超管ID
      'status' => 1
    ];
    $addres = Db::name('sys_user')->replace()->insertGetId($data);
    if ($addres) {
      $newdata = Db::name('sys_user')->where('id', $addres)->find();
      if ($newdata) {
        $data = [];
        $data['sz_salt'] = md5(create_guid());
        $data['pwd'] = encrypt_pass($pwd, $data['sz_salt'],  $newdata['create_time']);
        $res = Db::name('sys_user')->where('id', $newdata['id'])->update($data);
        return $res;
      }
    }
    return false;
  }

  public function add_client()
  {
    $postData = cache('install_data');
    $data = [
      'type' => 0,
      'app_id' => cache('install_appid'),
      'app_salt' => cache('install_appSecret'),
      'name' => '后台前端',
      'reg_ip' => $postData['domain'],
      'desc' => $postData['domain'],
      'status' => 1,
      'create_time' => time()
    ];
    $res = Db::name('sys_client')->replace()->insertGetId($data);
    return $res;
  }

  //删除安装文件
  // public function delinstall()
  // {
  //   $res = [];
  //   if (is_file(root_path('data') . 'install.lock')) {
  //     // $flag = @unlink(root_path('data') . 'install.lock');
  //     $flag = 1;
  //     if ($flag) {
  //       $res['msg'] = "安装文件删除成功！";
  //       $res['status'] = 1;
  //       return json($res);
  //     }
  //   }
  //   $res['msg'] = "安装文件删除失败！";
  //   $res['status'] = 0;
  //   return json($res);
  // }
}
